/*
 * Created on Apr 8, 2006
 */
package com.mgmaps.gps;

import javax.microedition.location.*;
import com.mgmaps.app.APPSettings;
import com.mgmaps.tools.StringTools;
import com.mgmaps.utils.*;

/**
 * Internal JSR-179 GPS receiver. Also processes NMEA statements obtained using getExtraInfo().
 */
public class GPSInternal extends GPSNMEA implements LocationListener {
  
  private Criteria crit;
  private LocationProvider provider;
  private Location updatedLocation;
  private QualifiedCoordinates lastQC;

  // interval in SECONDS
  private static final int UPDATE_INTERVAL = 1;
  
  // private String devName;
  // private String carrier;
  
  /**
   * Connect.
   */
  public boolean connect() {
    if (!connected && crit == null)
      try {
        // location provider criteria
        crit = new Criteria();
        if (APPSettings.isBlackberry) {
          // yes or no, set default at startup
          if (APPSettings.gpsCostAllowed == 0)
            // if (devName != null && devName.startsWith("95") &&
            //     carrier != null && carrier.trim().toLowerCase().indexOf("verizon") >= 0)
            crit.setCostAllowed(false);
          else
            crit.setCostAllowed(true);
          /* else if (Settings.gpsCostAllowed == 1)
            crit.setCostAllowed(true);
          else
            crit.setCostAllowed(false); */
          crit.setPreferredPowerConsumption(Criteria.POWER_USAGE_MEDIUM);
          crit.setPreferredResponseTime(16);
          crit.setHorizontalAccuracy(100);
        }
        provider = LocationProvider.getInstance(crit);
        // provider.setLocationListener(this, UPDATE_INTERVAL, UPDATE_INTERVAL, UPDATE_INTERVAL);
        // if (Settings.gpsNeedsUpdateInterval) // siemens SXG75
        //   provider.setLocationListener(this, UPDATE_INTERVAL, UPDATE_INTERVAL, -1);
        // else
        if (APPSettings.isBlackberry)
          provider.setLocationListener(this, UPDATE_INTERVAL, -1, -1);
        else
          provider.setLocationListener(this, UPDATE_INTERVAL, 1, 1);
      }
      catch (Exception ex) {
        ExtLogger.handle(ex, false, "Error initializing location services");
      }
    
    // do nothing
    connected = true;
    return true;
  }

  /**
   * Nothing to do at disconnect, just notify.
   * 
   * @see com.mgmaps.gps.GPSReceiver#disconnect()
   */
  public synchronized void disconnect(boolean notifyFlag) {
    if (provider != null)
      provider.reset();
    if (notifyFlag)
      notify();
  }

  /**
   * Called when the location is updated.
   * @param prov provider
   * @param loc new location
   * @see javax.microedition.location.LocationListener#locationUpdated(javax.microedition.location.LocationProvider, javax.microedition.location.Location)
   */
  public void locationUpdated(LocationProvider prov, Location loc) {
    synchronized(this) {
      updatedLocation = loc;
      notify();
    }
  }
  
  /**
   * Called when provider state has changed
   * @param prov provider
   * @param newState new state of provider
   * @see javax.microedition.location.LocationListener#providerStateChanged(javax.microedition.location.LocationProvider, int)
   */
  public void providerStateChanged(LocationProvider prov, int newState) {
    // not used
  }
  
  /**
   * Main method of the thread.
   * 
   * @see java.lang.Runnable#run()
   */
  public void run() {
    Location loc = null;
    
    while (!isQuitting()) {
      if (!isActive()) {
        doSleep();
        continue;
      }
      
      if (!isConnected())
        connect();

      while (isConnected() && !isQuitting()) {
        synchronized (this) {
          if (updatedLocation == null)
            try {
              wait();
            }
            catch (InterruptedException ie) {
            }
          
          loc = updatedLocation;
          updatedLocation = null;
        }
      
        if (loc != null && loc.isValid())
          parseLocationInfo(loc);
        // else
        //   currentFix = false;
      }
    }
  }
  
  /**
   * Parse location info and set the variables.
   * 
   * @param loc location processed
   */
  protected void parseLocationInfo(Location loc) {
    // loc & qc
    lastQC = loc.getQualifiedCoordinates();
    if (lastQC != null) {
      hasFix = true;
      fixTime = loc.getTimestamp();
      if (fixTime <= 0) {
        fixTime = System.currentTimeMillis();
        clockDelta = 0;
      }
      else
        clockDelta = System.currentTimeMillis()-fixTime;
      lat = lastQC.getLatitude();
      lon = lastQC.getLongitude();
      speed = loc.getSpeed() * 3.6;
      if (speed != 0)
        heading = loc.getCourse();
      else
        heading = Double.NaN;
      altitude = lastQC.getAltitude();
      precision = lastQC.getHorizontalAccuracy();
    }

    if (!APPSettings.isBlackberry) {
      // extra info
      String extraInfo = loc.getExtraInfo("application/X-jsr179-location-nmea");
      if (extraInfo != null) {
        // split by $
        String[] splits = StringTools.split(extraInfo, '$');
        for (int i=0; i<splits.length; i++)
          parse("$" + splits[i].trim());
      }
    }
  }
}
